/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ipti.br.tag.bo;

import com.itextpdf.text.DocumentException;
import org.ipti.br.tag.entity.Actor;
import org.ipti.br.tag.entity.Human;
import org.ipti.br.tag.entity.Unity;
import org.ipti.br.tag.entity.enums.WeekDay;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import javax.ejb.Stateless;
import javax.inject.Inject;
import org.ipti.br.tag.bean.SessionBean;
import org.ipti.br.tag.entity.UnitySchedule;
import org.ipti.br.tag.pdf.DeclarationPDF;
import org.ipti.br.tag.pdf.StudentPerUnityPdf;

/**
 *
 * @author ipti
 */
@Stateless
public class ReportBO {

    @Inject
    private SessionBean sessionBean;
    @Inject
    private PersonageBO personageBO;
    @Inject
    UnityScheduleBO unityScheduleBO;
    @Inject
    SimpleFrequencyBO simpleFrequencyBO;
    @Inject
    HumanBO humanBO;
    @Inject
    private UnityBO unityBO;

    public void reportStudentsPerUnity(Unity selectedUnity, Unity loggedUnity)
            throws IOException, FileNotFoundException, DocumentException {

        List<Actor> actorList = unityBO.getStudentsBySchool(selectedUnity);
        ArrayList<Human> humanList = new ArrayList<Human>();
        for (Actor actor : actorList) {
            Human h = humanBO.find(actor.getPerson().getId());
            humanList.add(h);
        }

        new StudentPerUnityPdf().run(selectedUnity, loggedUnity, humanList);
    }

    public void declaration() throws FileNotFoundException, DocumentException, IOException {

        DeclarationPDF d = new DeclarationPDF();
        Long personageID = 623403461L;

        Unity unitySchool = sessionBean.getLoggedActor().getUnity();
        List<Unity> unityList = unityBO.findSectorEducational(
                unityBO.unityChildrenPerOrganization(unitySchool, personageBO.find(personageID).getOrganization()),
                Calendar.getInstance().get(Calendar.YEAR));

        List<Actor> actorList = new ArrayList<Actor>();

        for (Unity u : unityList) {
            List<Actor> aluninhos = unityBO.getStudentsBySchool(u);
            for (Actor a : aluninhos) {
                actorList.add(a);
            }
        }


        Collections.sort(actorList, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Human h1 = (Human) ((Actor) o1).getPerson();
                Human h2 = (Human) ((Actor) o2).getPerson();
                return h1.getName().trim().compareTo(h2.getName().trim());
            }
        });

        List<int[]> cargaHoraria = new ArrayList<int[]>();
        List<long[]> numberOfFaults = new ArrayList<long[]>();
        List<int[]> frequency = new ArrayList<int[]>();

        int count = 0;
        for (Actor a : actorList) {
            if (a.getPersonage().getOrganization().getOrg_father().getName().equals("Fundamental Maior")) {
                cargaHoraria.add(getCargaHoraria(a));
            } else {
                cargaHoraria.add(getSchoolDays(a.getUnity(), a));
            }

            numberOfFaults.add(getNumberOfFaults(a.getUnity(), a));
            frequency.add(getFrequency(cargaHoraria.get(count), numberOfFaults.get(count)));
            count++;
        }
        d.run(unitySchool, cargaHoraria, numberOfFaults, frequency, actorList);
    }

    private int[] getSchoolDays(Unity unity, Actor actor) {
        Calendar finalDt = Calendar.getInstance();
        Calendar initialDt = actor.getActivated();
        Calendar date = Calendar.getInstance();

        int[] schoolDays = new int[12];


        if ((unity.getDeactivated() == null)
           || ( finalDt.get(Calendar.YEAR)  <= unity.getDeactivated().get(Calendar.YEAR)
           && finalDt.get(Calendar.MONTH) <= unity.getDeactivated().get(Calendar.MONTH)+3   
           && finalDt.get(Calendar.DATE)  <= unity.getDeactivated().get(Calendar.DATE)
           && finalDt.after(unity.getActivated()))) {

//            int numberOfMonths = ((finalDt.get(Calendar.YEAR) * 12 + finalDt.get(Calendar.MONTH))
//                    - (initialDt.get(Calendar.YEAR) * 12 + initialDt.get(Calendar.MONTH)));


            int initialMonth = initialDt.get(Calendar.YEAR) == finalDt.get(Calendar.YEAR) ? initialDt.get(Calendar.MONTH) : 0;
            int finalMonth = initialDt.get(Calendar.YEAR) == finalDt.get(Calendar.YEAR) ? 11 : finalDt.get(Calendar.MONTH);

            for (int i = initialMonth; i <= finalMonth; i++) {
                int initialDay = initialDt.get(Calendar.MONTH) == i ? initialDt.get(Calendar.DAY_OF_MONTH) : 1;

                date.set(date.get(Calendar.YEAR), i, initialDay);

                int finalDay = date.getActualMaximum(Calendar.DAY_OF_MONTH);

                schoolDays[i] = 0;
                for (int j = initialDay; j <= finalDay; j++) {
                    date.set(date.get(Calendar.YEAR), i, j);
                    if (WeekDay.getDay(date.get(Calendar.DAY_OF_WEEK)).isWorkday()) {
                        schoolDays[i]++;
                    }
                }

            }
        }
        return schoolDays;
    }

    private int[] getCargaHoraria(Actor actor) {
        int[] cargaHoraria = new int[12];

        Calendar finalDt = Calendar.getInstance();
        Calendar initialDt = actor.getActivated();
        Calendar date = Calendar.getInstance();

        Unity unity = actor.getUnity();

        if ((unity.getDeactivated() == null)
           || ( finalDt.get(Calendar.YEAR)  <= unity.getDeactivated().get(Calendar.YEAR)
           && finalDt.get(Calendar.MONTH) <= unity.getDeactivated().get(Calendar.MONTH)+3   
           && finalDt.get(Calendar.DATE)  <= unity.getDeactivated().get(Calendar.DATE)
           && finalDt.after(unity.getActivated()))) {

            int initialMonth = initialDt.get(Calendar.YEAR) == finalDt.get(Calendar.YEAR) ? initialDt.get(Calendar.MONTH) : 0;
            int finalMonth = initialDt.get(Calendar.YEAR) == finalDt.get(Calendar.YEAR) ? 11 : finalDt.get(Calendar.MONTH);

            List<Long> workDayList = unityScheduleBO.getUnityScheduleDAO().AulasPorDiaDaSemana(unity);


            for (int i = initialMonth; i <= finalMonth; i++) {
                int initialDay = initialDt.get(Calendar.MONTH) == i ? initialDt.get(Calendar.DAY_OF_MONTH) : 1;

                date.set(date.get(Calendar.YEAR), i, initialDay);

                int finalDay = date.getActualMaximum(Calendar.DAY_OF_MONTH);

                cargaHoraria[i] = 0;
                for (int j = initialDay; j <= finalDay; j++) {
                    date.set(date.get(Calendar.YEAR), i, j);
                    if (WeekDay.getDay(date.get(Calendar.DAY_OF_WEEK)).isWorkday()) {
                        cargaHoraria[i] += workDayList.get(WeekDay.getDay(date.get(Calendar.DAY_OF_WEEK)).ordinal());
                    }
                }
            }
        }



        return cargaHoraria;
    }

    public long[] getNumberOfFaults(Unity unity, Actor actor) {
        Calendar finalDt = Calendar.getInstance();
        Calendar initialDt = actor.getActivated();
        int year = finalDt.get(Calendar.YEAR);

        long[] numberOfFaults = new long[12];

        if ((unity.getDeactivated() == null)
           || ( finalDt.get(Calendar.YEAR)  <= unity.getDeactivated().get(Calendar.YEAR)
           && finalDt.get(Calendar.MONTH) <= unity.getDeactivated().get(Calendar.MONTH)+3   
           && finalDt.get(Calendar.DATE)  <= unity.getDeactivated().get(Calendar.DATE)
           && finalDt.after(unity.getActivated()))) {

            int initialMonth = initialDt.get(Calendar.YEAR) == finalDt.get(Calendar.YEAR) ? initialDt.get(Calendar.MONTH) : 0;
            int finalMonth = initialDt.get(Calendar.YEAR) == finalDt.get(Calendar.YEAR) ? 11 : finalDt.get(Calendar.MONTH);

            for (int i = initialMonth; i <= finalMonth; i++) {
                int initialDay = initialDt.get(Calendar.MONTH) == i ? initialDt.get(Calendar.DAY_OF_MONTH) : 1;
                Calendar initialDate = Calendar.getInstance();
                initialDate.set(year, i, initialDay);

                int finalDay = initialDate.getActualMaximum(Calendar.DAY_OF_MONTH);
                Calendar finalDate = Calendar.getInstance();
                finalDate.set(year, i, finalDay);

                if (unity.getDeactivated() != null && unity.getDeactivated().get(Calendar.MONTH) > i) {
                    numberOfFaults[i] = -1;
                } else {    
                    numberOfFaults[i] = simpleFrequencyBO.getSimpleFrequencyDAO().countFaults(actor, initialDate, finalDate);
                }
            }
        }
        return numberOfFaults;

    }

    public int[] getFrequency(int[] days, long[] numberOfFaults) {

        int[] frequency = new int[12];
        for (int i = 0; i < 12; i++) {
            if (numberOfFaults[i] == -1) {
                frequency[i] = -1;
            } else {
                frequency[i] = days[i] != 0 ? (int) (100 * (days[i] - numberOfFaults[i])) / days[i] : 100;
            }
        }

        return frequency;
    }
}